using System;
using System.Collections;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using ThemeChain;
using jQueryApi;

namespace Nsb.Classes
{
    [IgnoreNamespace]
    public class Ask : Actor
    {
        // ReSharper disable MemberCanBeProtected.Global
        // ReSharper disable MemberCanBePrivate.Global
        // ReSharper disable ConvertToConstant.Global
        // ReSharper disable FieldCanBeMadeReadOnly.Global
        [PreserveCase, PreserveName] public const int FadeSpeed = 250;
        [PreserveCase, PreserveName] public Dictionary Attr;
        [PreserveCase, PreserveName] public string CancelFace = "Cancel";
        [PreserveCase, PreserveName] public ActionO Complete;
        [PreserveCase, PreserveName] public Dictionary Css;
        [PreserveCase, PreserveName] public Action Customize;
        [PreserveCase, PreserveName] public Action Finally;
        [PreserveCase, PreserveName] public jQueryObject Html;
        [PreserveCase, PreserveName] public string InputType;
        [PreserveCase, PreserveName] public string Message;
        [PreserveCase, PreserveName] public string Msg;
        [PreserveCase, PreserveName] public string OkFace = "OK";
        [PreserveCase, PreserveName] public string SkipFace = "Skip";
        [PreserveCase, PreserveName] public string Title = "";
        [PreserveCase, PreserveName] public string Value;
        [PreserveCase, PreserveName] public ActionB Verify;
        // ReSharper restore FieldCanBeMadeReadOnly.Global
        // ReSharper restore ConvertToConstant.Global
        // ReSharper restore MemberCanBePrivate.Global
        // ReSharper restore MemberCanBeProtected.Global

        private Await _awp;

        public Ask()
        {
            Element = jQuery.FromHtml("<div class='Ask AboveHider'/>")
                .CSS(new Dictionary("position", "absolute"))
                .Plugin<Jewl>().Draggable(new Dictionary())
                ;
            jQuery.Document.Trigger("Asking");
        }

        public jQueryObject CancelBtn
        {
            get { return jQuery.Select(".CancelBtn", Element); }
        }

        [AlternateSignature]
        public static extern void Ok(string msg);

        public static void Ok(Dictionary properties)
        {
            if (Type.GetScriptType(properties) == "string")
                properties = new Dictionary("Msg", (string) (object) properties);

            new Await()
                .AddAw(new Ask().OkAw, properties)
                .Commit();
        }

        [AlternateSignature]
        public extern void OkAw(Await awp, string message);

        public void OkAw(Await awp, Dictionary properties)
        {
            StdTitle(awp, properties);
            StdContent();
            StdBtns(OkEv);
            FocusElementAw(Await.AsyncAw, jQuery.Select(".OkBtn", Element));
        }

        [AlternateSignature]
        public extern void OkCancelAw(Await awp, string message);

        public void OkCancelAw(Await awp, Dictionary properties)
        {
            StdTitle(awp, properties);
            StdContent();
            StdBtns(OkEv, CancelEv);
            FocusElementAw(Await.AsyncAw, jQuery.Select(".OkBtn", Element));
        }

        [AlternateSignature]
        public extern void TextAw(Await awp, string message);

        public void TextAw(Await awp, Dictionary properties)
        {
            InputType = InputType ?? "text";
            StdTitle(awp, properties);

            jQuery.FromHtml("<input type='" + InputType + "' class='Content'/>")
                .AppendTo(Element)
                .Value(Value ?? "")
                .CSS(Css ?? new Dictionary())
                .Attribute(Attr ?? new Dictionary())
                ;

            StdBtns(OkTextEv, CancelEv);

            FocusElementAw(Await.AsyncAw, jQuery.Select("input[type=" + InputType + "]", Element));
        }

        /// <summary>
        /// Ask to change text offerred in a pop up textarea box
        /// </summary>
        /// <param name="awp">Awaiter</param>
        /// <param name="properties">Dictionary including Msg and Value fields</param>
        public void TextAreaAw(Await awp, Dictionary properties)
        {
            StdTitle(awp, properties);

            jQueryObject textarea = jQuery.FromHtml("<textarea class='Content' wrap='hard'/>")
                .AppendTo(Element)
                .Value(Value ?? "")
                .CSS(Css ?? new Dictionary("height", "50px"))
                .Attribute(Attr ?? new Dictionary())
                ;

            StdBtns(OkTextAreaEv, CancelEv);

            Element
                .Unbind("keydown.ret")
                .Bind("keydown.ask",
                      delegate(jQueryEvent e)
                      {
                          if (e.Which == 9)
                          {
                              CancelEvent(e);
                              Helpers.InsertText(textarea, "\t");
                          }
                      })
                ;

            Keys.FilterAll(Element);

            FocusElementAw(Await.AsyncAw, textarea);
        }

        public void FileUploadAw(Await awp, Dictionary properties)
        {
            StdTitle(awp, properties);

            if (properties["action"] != null)
            {
                ThemeBase.PageAction((Action) properties["action"]);
            }

            jQueryObject form = jQuery.FromHtml("<form enctype='multipart/form-data' action='" + Uri.Join(ThemeBase.AppUri, "/upload.php") + "' method='POST'/>")
                .AppendTo(Element)
                ;

            jQuery.FromHtml(string.Format("<input type='hidden' name='goto' value='{0}'/>", Uri.Path(Window.Location.Href)))
                .AppendTo(form)
                ;

            jQuery.FromHtml(string.Format("<input type='hidden' name='password' value='{0}'/>", properties["password"]))
                .AppendTo(form)
                ;

            jQuery.FromHtml(string.Format("<input type='hidden' name='path' value='{0}'/>", properties["path"]))
                .AppendTo(form)
                ;

            jQuery.FromHtml(string.Format("<input type='hidden' name='filename' value='{0}'/>", properties["filename"]))
                .AppendTo(form)
                ;

            jQuery.FromHtml("<input type='file' name='thefile' class='Content'/>")
                .AppendTo(form)
                ;

            StdBtns(OkFileUploadEv, CancelFileUploadEv);

            FocusElementAw(Await.AsyncAw, jQuery.Select("input[type=text]", Element));
        }

        protected void StdTitle(Await awp, Dictionary properties)
        {
            _awp = awp;

            if (!TryLoadProperties(properties))
            {
                Message = properties.ToString();
            }

            jQuery.FromHtml("<h1/>")
                .AppendTo(Element)
                .Html(Msg ?? Message)
                ;

            if (Html != null)
            {
                Html.AppendTo(Element);
                Window.SetTimeout(delegate { jQuery.Select("input", Html).First().Focus(); }, 1);
            }
        }

        protected void StdContent()
        {
            jQuery.FromHtml("<div class='Content'/>")
                .AppendTo(Element)
                ;
        }

        [AlternateSignature]
        protected extern void StdBtns(jQueryEventHandler okEv);

        protected void StdBtns(jQueryEventHandler okEv, jQueryEventHandler cancelEv)
        {
            if (cancelEv != null)
                jQuery.FromHtml("<button class='CancelBtn'/>")
                    .AppendTo(Element)
                    .Html(CancelFace)
                    .Click(cancelEv)
                    ;

            jQuery.FromHtml("<button class='OkBtn'/>")
                .AppendTo(Element)
                .Html(OkFace)
                .Click(okEv)
                ;

            Hider(true);

            Element
                .Hide()
                .AppendTo(Document.Body)
                .Bind("keydown.ret", delegate(jQueryEvent e) { Keys.RetKey(e, okEv); })
                .Bind("keydown.shiftret", delegate(jQueryEvent e) { Keys.ShiftRetKey(e, okEv); })
                .Bind("keydown.esc", delegate(jQueryEvent e) { Keys.EscKey(e, cancelEv ?? CancelEv); })
                .Plugin<Jewl>().FadeInW(FadeSpeed)
                .Plugin<Jewl>().Position(new Dictionary("my", "center top", "at", "center top", "of", Window.Self, "offset", "0 200", "collision", "fit fit"))
                ;

            Keys.FilterAll(Element);

            if (Customize != null)
                Customize();
        }

        protected void OkTextEv(jQueryEvent e)
        {
            DestroyEv(e, jQuery.Select("input[type=" + InputType + "]", Element).GetValue().Trim());
        }

        protected void OkTextAreaEv(jQueryEvent e)
        {
            DestroyEv(e, jQuery.Select("textarea", Element).GetValue());
        }

        protected void OkFileUploadEv(jQueryEvent e)
        {
            if (Finally != null)
                Finally();
            jQueryObject name = jQuery.Select("input[type=file]", Element);
            if (String.IsNullOrEmpty(name.GetValue()))
            {
                Ok("Please choose a file to upload.");
                return;
            }
            jQueryObject form = jQuery.Select("form", Element);
            form.Submit();
        }

        protected void OkEv(jQueryEvent e)
        {
            DestroyEv(e, true);
        }

        protected void CancelEv(jQueryEvent e)
        {
            DestroyEv(e, false);
        }

        protected void CancelFileUploadEv(jQueryEvent e)
        {
            Storage.RemoveSession(ThemeBase.PageActionKey);
            DestroyEv(e, false);
        }

        protected void DestroyEv(jQueryEvent e, object value)
        {
            // Verify function is responsible for informing of errors if needed
            if (Type.GetScriptType(value) != "boolean" || (bool) value)
            {
                if (Verify != null && !Verify(value)) return;
                if (Complete != null)
                    value = Complete(value);
            }
            if (Finally != null)
                Finally();
            CancelEvent(e);
            Hider(false);
            Element
                .Plugin<Jewl>()
                .FadeOutW(FadeSpeed,
                          delegate
                          {
                              Element.Remove();
                              _awp.DoneWith(ResultRx, value);
                              jQuery.Document.Trigger("AskingDone");
                              jQuery.Document.Trigger("PageDefaultFocus");
                          }
                );
        }
    }
}